/* Copyright 2001,2002,2003 NAH6
 * All Rights Reserved
 *
 * Parts Copyright DoD, Parts Copyright Starium
 *
 */
/*LINTLIBRARY*/
/*PROTOLIB1*/

#include "main.h"
#ifdef FLOATING_POINT
#include "showdata.h"
#endif
/*#include <math.h>*/
#include "con_adap.h"
#include "con_stch.h"
#include "interp.h"
#include "lp_syn.h"
#include "move_array16.h"
#include "postfilt.h"
#include "zero_array16.h"
#include "synth.h"
#include "filter.h"
#include <stdio.h>


STATIC void SquelchTest(
int     len,
fxpt_16 speech[]);

STATIC int clip(
fxpt_16 s[],
int     l);

/**************************************************************************
*                                                                         *
* ROUTINE
*               Synthesis
*
* FUNCTION
*               CELP synthesis
* SYNOPSIS
*               Synthesis(parameters, BitIntegrity, frame_num, speech_out)
*
*   formal
*
*                       data    I/O
*       name            type    type    function
*       -------------------------------------------------------------------
*       parameters      TX_PARAM i      Frame of CELP parameters
*       BitIntegrity    INTEGRITY i     Integrity of decoded bitstream (future)
*       frame_num       int      i      Frame number
*       speech_out      fxpt_16  o      Frame of output speech
*
**************************************************************************/
void Synthesis(TX_PARAM parameters, fxpt_16 speech_out[F_LEN])
{
        fxpt_16         lsfint[NUM_SF][ORDER];  /* 0.15 format */
        fxpt_16         excitation[SF_LEN];     /* 15.0 format */
        static fxpt_16  adapt_cw[ACB_SIZE];     /* 15.0 format */
        fxpt_16         lpc_speech[SF_LEN];     /* 15.0 format */
        fxpt_16         post_speech[SF_LEN];    /* 15.0 format */
        int             sf;
        static int      first=TRUE;
#if 0
        static FILE     *fp_lpcfile, *fp_postfile;
#endif

        /*  Initialize */
        if (first) {
                first = FALSE;
                ZeroArray16(adapt_cw, ACB_SIZE);
        }

        /* Interpolate NUM_SF subframes of LSFs for subframe synthesis */
        Interpolate(parameters.lsf, lsfint, SYNTHESIS);

        /* Synthesisze speech on a subframe basis */
        for (sf = 0; sf < NUM_SF; sf++) {

                /* Construct the stochastic codeword (initial excitation) */
                ConstructStochCW(parameters.StochasticIndex[sf],
                    parameters.StochasticGain[sf], excitation);

                /* Construct the adaptive codeword and update excitation */
                ConstructAdaptCW(excitation, adapt_cw,
                    parameters.AdaptiveGain[sf], parameters.AdaptiveDelay[sf]);

                /* Perform LP excitation to produce speech */
                LP_Synthesis(excitation, lsfint[sf], lpc_speech);

#if 0
{
        int i;
        for (i=0; i<SF_LEN; i+=4)
                printf("lpc_speech[%d] = { %5d, %5d, %5d, %5d }\n", i,
                    lpc_speech[i], lpc_speech[i+1], lpc_speech[i+2],
                    lpc_speech[i+3]);
}
#endif

                /* Write unfiltered output speech to disk */
                /*ShowData(&fp_lpcfile, "Short4_NPF.spd", lpc_speech, FLOAT2SHORT, SF_LEN);*/

                /* Apply post filter to lpc-speech */
#ifdef POSTFILTER
                PostFilter(lpc_speech, lsfint[sf], post_speech);
#else
                MoveArray16(post_speech, lpc_speech, SF_LEN);
#endif

                /*  Write postfiltered output speech to disk */
                /*ShowData(&fp_postfile, "Short4_PF.spd", post_speech, FLOAT2SHORT, SF_LEN);*/

                /* Test for clipping */
//                SquelchTest(SF_LEN, post_speech);

#ifndef STREAMLINE
                /* Apply high pass filter to speech */
                HPF_OutSpeech(post_speech, &speech_out[sf*SF_LEN]);
#else
                /* Copy postfiltered speech to output buffer */
                MoveArray16(&speech_out[sf*SF_LEN], post_speech, SF_LEN);
#endif
        }
}

/**************************************************************************
*                                                                         *
* ROUTINE
*               SquelchTest
*
* FUNCTION
*               Test for clipping on input speech
* SYNOPSIS
*               SquelchTest(len, frame_num, speech)
*
*   formal
*
*                       data    I/O
*       name            type    type    function
*       -------------------------------------------------------------------
*       len             int      i      Length of speech buffer
*       frame_num       int      i      Frame Number
*       speech_out      fxpt_16 i/o     Frame of speech
*
**************************************************************************/

void SquelchTest(
int     len,
fxpt_16 speech[])
{
        int     i;

        while (clip(speech, len)) {
                CELP_PRINTF(("celp: Clipping detected in frame\n"));
                for(i=0;i<len;i++)
                        /*speech[i] = 0.05 * speech[i];*/
                        speech[i] = fxpt_mult16_fast(speech[i], 1638);
        }
}

/**************************************************************************
*
* ROUTINE
*               clip
*
* FUNCTION
*               Determine if speech is clipped
*
* SYnoPSIS
*               clip(s, l)
*
*   formal
*
*                       data    I/O
*       name            type    type    function
*       -------------------------------------------------------------------
*       s               fxpt_16 i       input speech
*       l               int     i       length of input speech
*
***************************************************************************
*
* CALLED BY
*
*       celp
*
**************************************************************************/

int clip(
fxpt_16 s[],
int     l)
{
        int i, count;

        /* Count number of clippings */

        count = 0;
        for (i=0; i<l; i++) {
                if ((s[i] == 32767) || (s[i] == -32768))
                        count++;
        }

        /* Clipping heuristics (could also use energy, delta energy, etc.) */

        return (count >= 10 ? TRUE : FALSE);
}
